package com.yhy.wxzn.wcs.device.netty;

import com.yhy.wxzn.wcs.device.netty.bean.ResultData;
import com.yhy.wxzn.wcs.device.netty.bean.SiemensMessage;
import com.yhy.wxzn.wcs.device.netty.commons.Utility;
import com.yhy.wxzn.wcs.device.netty.decoder.SiemensDecoder;
import com.yhy.wxzn.wcs.device.netty.encoder.SiemensEncoder;
import com.yhy.wxzn.wcs.device.netty.enumerate.CommandType;
import com.yhy.wxzn.wcs.device.netty.enumerate.DataType;
import com.yhy.wxzn.wcs.device.netty.enumerate.SiemensPLCS;
import com.yhy.wxzn.wcs.device.netty.handler.SiemensHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class SiemensNet {
    private static final Logger log = LoggerFactory.getLogger(SiemensNet.class);
    private final int timeOut = 5;
    private final int plcPort = 102;
    private String plcIP = "127.0.0.1";
    private Bootstrap bootstrap = new Bootstrap();
    private EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
    private SiemensHandler siemensHandler = new SiemensHandler();
    private String errorMsg = "msg";

    public SiemensNet(SiemensPLCS type) {
        this.siemensHandler.setHead(type);
        this.bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
        ((Bootstrap)((Bootstrap)((Bootstrap)((Bootstrap)this.bootstrap.group(this.eventLoopGroup)).channel(NioSocketChannel.class)).option(ChannelOption.TCP_NODELAY, true)).option(ChannelOption.SO_KEEPALIVE, true)).handler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel channel) throws Exception {
                channel.pipeline().addLast("SiemensDecoder", new SiemensDecoder());
                channel.pipeline().addLast("SiemensEncoder", new SiemensEncoder());
                channel.pipeline().addLast("SiemensHandler", SiemensNet.this.siemensHandler);
            }
        });
    }

    public boolean isConnectd() {
        boolean isOk = false;
        if (this.siemensHandler != null) {
            isOk = this.siemensHandler.isConnectd();
        }

        return isOk;
    }

    public void connect() {
        if (!StringUtil.isNullOrEmpty(this.plcIP)) {
            this.connect(this.plcIP);
        }
    }

    public void connect(String host) {
        if (!this.isConnectd()) {
            this.plcIP = host;

            try {
                ChannelFuture channelFuture = this.bootstrap.connect(host, 102);
                channelFuture.awaitUninterruptibly();
                if (!channelFuture.isSuccess()) {
                    this.showErrorMsg("连接PLC [" + host + "]超时！");
                    return;
                }

                if (channelFuture.isSuccess()) {
                    try {
                        Thread.sleep(1500L);
                    } catch (InterruptedException var4) {
                        this.showErrorMsg("connect:" + var4.getMessage());
                    }
                }
            } catch (Exception var5) {
                var5.printStackTrace();
            }

        }
    }

    public void close() {
        if (this.eventLoopGroup != null) {
            this.eventLoopGroup.shutdownGracefully();
        }

        log.info("关闭连接，释放对象！");
    }

    public ResultData read(String address) {
        return this.readBytes(address, 0);
    }

    public ResultData readBytes(String address, int count) {
        ResultData rd = new ResultData();
        rd.setConnecd(false);
        rd.setSuccess(false);
        rd.setMessage("当前与PLC通信断开！");
        if (this.isConnectd()) {
            SiemensMessage msg = Utility.getAddress(address);
            if (msg == null) {
                rd.setMessage("请输入正确的PLC地址！");
                return rd;
            }

            try {
                msg.setType(CommandType.Read);
                if (count > 0) {
                    if (msg.getDataType() != DataType.Byte) {
                        rd.setSuccess(false);
                        rd.setMessage("对不起，请输入Byte类型地址！");
                        return rd;
                    }

                    msg.setDataType(DataType.Bytes);
                    msg.setDataLength(count);
                } else {
                    msg.setDataLength(msg.getDataType().getValue());
                }

                SiemensMessage result = this.send(msg);
                if (result.isSuccess()) {
                    Object value = this.getValue(result.getDataValue(), result.getDataType(), result.getDataLength());
                    rd.setValue(value);
                }

                rd.setSuccess(result.isSuccess());
                if (this.isConnectd()) {
                    rd.setMessage(result.getMessage());
                }

                rd.setConnecd(this.isConnectd());
            } catch (Exception var7) {
                rd.setMessage(var7.getMessage());
            }
        }

        return rd;
    }

    private Object getValue(ByteBuf in, DataType type, int dataLength) {
        Object value = null;
        switch(type) {
            case Bit:
                value = in.readByte() == 1;
                break;
            case Byte:
                value = in.readByte();
                break;
            case Word:
                value = in.readShort();
                break;
            case Dint:
                value = in.readInt();
                break;
            case Long:
                value = in.readLong();
                break;
            case Bytes:
                byte[] buffer = new byte[dataLength];
                in.readBytes(buffer);
                value = buffer;
        }

        ReferenceCountUtil.release(in);
        return value;
    }

    public ResultData write(String address, boolean value) {
        return this.write(address, (byte)(value ? 1 : 0));
    }

    public ResultData write(String address, byte value) {
        ByteBuf buf = Unpooled.buffer(1);
        buf.writeByte(value);
        return this.write(address, buf);
    }

    public ResultData write(String address, short value) {
        ByteBuf buf = Unpooled.buffer(2);
        buf.writeShort(value);
        return this.write(address, buf);
    }

    public ResultData write(String address, int value) {
        ByteBuf buf = Unpooled.buffer(4);
        buf.writeInt(value);
        return this.write(address, buf);
    }

    public ResultData write(String address, long value) {
        ByteBuf buf = Unpooled.buffer(4);
        buf.writeLong(value);
        return this.write(address, buf);
    }

    public ResultData write(String address, byte[] value) {
        ByteBuf buf = Unpooled.wrappedBuffer(value);
        return this.write(address, buf);
    }

    private ResultData write(String address, ByteBuf value) {
        ResultData rd = new ResultData();
        rd.setConnecd(false);
        rd.setSuccess(false);
        rd.setMessage("当前与PLC通信断开！");
        if (this.isConnectd()) {
            rd.setConnecd(true);
            SiemensMessage msg = Utility.getAddress(address);
            if (msg == null) {
                rd.setMessage("当前PLC地址不正确！");
                return rd;
            }

            msg.setType(CommandType.Write);
            msg.setDataValue(value);
            msg.setDataLength(value.writerIndex());

            try {
                SiemensMessage result = this.send(msg);
                if (this.isConnectd()) {
                    rd.setMessage(result.getMessage());
                }

                rd.setSuccess(result.isSuccess());
                rd.setValue(result.getDataValue());
                rd.setConnecd(this.isConnectd());
            } catch (Exception var6) {
                rd.setMessage(var6.getMessage());
            }
        }

        return rd;
    }

    private synchronized SiemensMessage send(SiemensMessage message) throws InterruptedException, ExecutionException {
        ChannelPromise promise = this.siemensHandler.sendMessage(message);
        promise.await(5L, TimeUnit.SECONDS);
        return this.siemensHandler.getResponse();
    }

    private void showErrorMsg(String msg) {
        if (!this.errorMsg.equals(msg)) {
            this.errorMsg = msg;
            log.error(this.errorMsg);
        }

    }
}
